{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 多线程vs多进程\n",
    "- 进程：程序运行的一个状态\n",
    "    - 包含地址控件，内存，数据栈等\n",
    "    - 每个进程有自己完全独立的运行环境，多进程共享数据是一个问题\n",
    "- 线程：一个进程的独立运行片段，一个进程可以有多个线程\n",
    "    - 轻量化进程\n",
    "    - 一个进程的多个线程间共享数据和上下文运行环境\n",
    "    - 共享互斥问题\n",
    "    \n",
    "- 全局解释器锁（GIL）\n",
    "    - python的代码执行是由python虚拟机进行控制\n",
    "    - 在主循环中只能一个线程执行\n",
    "    - "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 多线程，传参数\n",
    "\n",
    "import time\n",
    "# 导入多线程包_thread更名为thread\n",
    "import _thread as thread\n",
    "\n",
    "def loop1(in1):\n",
    "    # ctime得到当前时间\n",
    "    print('start loop 1 at', time.ctime())\n",
    "    print('我是参数 ', in1)\n",
    "    time.sleep(4)\n",
    "    print('end loop 1 at', time.ctime())\n",
    "    \n",
    "def loop2(in1, in2):\n",
    "    # ctime得到当前时间\n",
    "    print('start loop 2 at', time.ctime())\n",
    "    print('我是参数 ', in2)\n",
    "    time.sleep(2)\n",
    "    print('end loop 2 at', time.ctime())    \n",
    "    \n",
    "def main():\n",
    "    print('starting at: ', time.ctime())\n",
    "    thread.start_new_thread(loop1,('cheng', ))\n",
    "    thread.start_new_thread(loop2,('cheng', 'fei'))\n",
    "    \n",
    "    print('All done at: ', time.ctime())\n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    main()\n",
    "    while True:\n",
    "        time.sleep(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## threading的使用\n",
    "    - 直接使用threading.Thread生成Thread实例\n",
    "        1. t = threading.Thread(target=xxx, args=(xxx, ))\n",
    "        2. t.start(): 启动多线程\n",
    "        3. t.join():等待多线程执行完成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "starting at:  Tue Oct 16 09:55:12 2018\n",
      "start loop 1 atstart loop 2 at Tue Oct 16 09:55:12 2018\n",
      "我是参数  fei\n",
      " Tue Oct 16 09:55:12 2018\n",
      "我是参数  cheng\n",
      "end loop 2 at Tue Oct 16 09:55:14 2018\n",
      "end loop 1 at Tue Oct 16 09:55:16 2018\n",
      "All done at:  Tue Oct 16 09:55:16 2018\n"
     ]
    }
   ],
   "source": [
    "# 案例\n",
    "import time\n",
    "# 导入多线程包threading\n",
    "import threading\n",
    "\n",
    "def loop1(in1):\n",
    "    # ctime得到当前时间\n",
    "    print('start loop 1 at', time.ctime())\n",
    "    print('我是参数 ', in1)\n",
    "    time.sleep(4)\n",
    "    print('end loop 1 at', time.ctime())\n",
    "    \n",
    "def loop2(in1, in2):\n",
    "    # ctime得到当前时间\n",
    "    print('start loop 2 at', time.ctime())\n",
    "    print('我是参数 ', in2)\n",
    "    time.sleep(2)\n",
    "    print('end loop 2 at', time.ctime())    \n",
    "    \n",
    "def main():\n",
    "    print('starting at: ', time.ctime())\n",
    "    t1 = threading.Thread(target = loop1, args=('cheng', ))\n",
    "    t1.start()\n",
    "    \n",
    "    t2 = threading.Thread(target=loop2, args=('cheng', 'fei'))\n",
    "    t2.start()\n",
    "    \n",
    "    t1.join()\n",
    "    t2.join()\n",
    "    print('All done at: ', time.ctime())\n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    main()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 守护线程- daemon\n",
    "    - 如果在程序中将子线程设置成守护线程，则子线程会在主线程结束的时候自动退出\n",
    "    - 用处：一般认为，守护线程不重要或者不允许离开主线程独立运行\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "main thread\n",
      "start fun\n",
      "main thread end\n",
      "end fun\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "import threading\n",
    "\n",
    "def fun():\n",
    "    print('start fun')\n",
    "    time.sleep(2)\n",
    "    print('end fun')\n",
    "print('main thread')\n",
    "\n",
    "t1 = threading.Thread(target=fun, args=())\n",
    "# 设置成守护线程\n",
    "t1.setDaemon(True)\n",
    "t1.start()\n",
    "\n",
    "time.sleep(1)\n",
    "print('main thread end')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 线程常用属性\n",
    "    - threading.currentThread:返回当前线程变量\n",
    "    - threading.enumerate：返回一个包含正在运行的线程的list，正在运行的线程指的是线程启动后，结束前\n",
    "    - threading.activeCount：返回正在运行的线程数量，效果跟len(threading.enumerate)相同\n",
    "    - thr.setName：给线程设置名字\n",
    "    - thr.getName: 得到线程的名字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "starting at:  Tue Oct 16 10:19:13 2018\n",
      "start loop 1 at:  Tue Oct 16 10:19:13 2018\n",
      "start loop 2 at:  Tue Oct 16 10:19:13 2018\n",
      "start loop 3 at:  Tue Oct 16 10:19:13 2018\n",
      "end loop 2 at:  Tue Oct 16 10:19:15 2018\n",
      "正在运行的线程名是： MainThread\n",
      "正在运行的线程名是： Thread-2\n",
      "正在运行的线程名是： Thread-3\n",
      "正在运行的线程名是： IPythonHistorySavingThread\n",
      "正在运行的线程名是： Thread-1\n",
      "正在运行的线程名是： THR_1\n",
      "正在运行的线程名是： THR_3\n",
      "正在运行的子线程数量为：7\n",
      "All done at:  Tue Oct 16 10:19:16 2018\n",
      "end loop 1 at:  Tue Oct 16 10:19:17 2018\n",
      "end loop 3 at:  Tue Oct 16 10:19:18 2018\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "# 导入多线程包threading\n",
    "import threading\n",
    "\n",
    "def loop1():\n",
    "    # ctime得到当前时间\n",
    "    print('start loop 1 at: ', time.ctime())\n",
    "    \n",
    "    time.sleep(4)\n",
    "    print('end loop 1 at: ', time.ctime())\n",
    "    \n",
    "def loop2():\n",
    "    # ctime得到当前时间\n",
    "    print('start loop 2 at: ', time.ctime())\n",
    "\n",
    "    time.sleep(2)\n",
    "    print('end loop 2 at: ', time.ctime())    \n",
    "    \n",
    "def loop3():\n",
    "    print('start loop 3 at: ', time.ctime())\n",
    "    time.sleep(5)\n",
    "    print('end loop 3 at: ', time.ctime())\n",
    "    \n",
    "def main():\n",
    "    print('starting at: ', time.ctime())\n",
    "    t1 = threading.Thread(target = loop1, args=( ))\n",
    "    t1.setName('THR_1')\n",
    "    t1.start()\n",
    "    \n",
    "    t2 = threading.Thread(target=loop2, args=())\n",
    "    t2.setName('THR_2')\n",
    "    t2.start()\n",
    "    \n",
    "    t3 = threading.Thread(target=loop3, args=())\n",
    "    t3.setName('THR_3')\n",
    "    t3.start()\n",
    "    \n",
    "    time.sleep(3)\n",
    "    for thr in threading.enumerate():\n",
    "        print('正在运行的线程名是： {0}'.format(thr.getName()))\n",
    "    \n",
    "    print('正在运行的子线程数量为：{0}'.format(threading.activeCount()))\n",
    "    print('All done at: ', time.ctime())\n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    main()\n",
    "    while True:\n",
    "        time.sleep(10)\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 共享变量\n",
    "    - 当多个线程同时访问一个变量的时候，会产生共享变量的问题\n",
    "    - 解决变量：锁，信号灯\n",
    "    - 锁（Lock）：\n",
    "        - 是一个标志，表示一个线程在占用一些资源\n",
    "        - 使用方法：\n",
    "            - 上锁\n",
    "            - 使用共享资源，放心的用\n",
    "            - 取消锁，释放锁\n",
    "        - 锁谁：哪个资源需要多个线程共享，锁哪个\n",
    "        - 理解锁：锁其实不是锁住谁， 而是一个令牌\n",
    "    - 线程安全问题：\n",
    "        - 如果一个资源/变量，他对于多线程来讲，不用加锁也不会引起任何问题，则称为线程安全\n",
    "        - 线程不安全变量类型：list，set，dict\n",
    "        - 线程安全变量类型：queue\n",
    "        \n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 共享变量问题\n",
    "import threading\n",
    "\n",
    "sum = 0\n",
    "loopSum = 10000\n",
    "\n",
    "def myAdd():\n",
    "    global sum, loopSum\n",
    "    for i in range(1, loopSum):\n",
    "        sum += 1\n",
    "        \n",
    "def myMinu():\n",
    "    global sum, loopSum\n",
    "    for i in range(1, loopSum):\n",
    "        sum -= 1\n",
    "        \n",
    "if __name__ == '__main__':\n",
    "    print('starting .... {0}'.format(sum))\n",
    "    \n",
    "    t1 = threading.Thread(target=myAdd, args=())\n",
    "    t2 = threading.Thread(target=myMinu, args=())\n",
    "    \n",
    "    t1.start()\n",
    "    t2.start()\n",
    "    \n",
    "    t1.join()\n",
    "    t2.join()\n",
    "    \n",
    "    print('done....{0}'.format(sum))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 生产者消费问题：\n",
    "    - 一个模型，可以用来搭建消息队列\n",
    "    - queue是一个用来存放变量的数据结构，特点是先进先出，内部元素排队，可以理解成一个特殊的list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Exception in thread Thread-6:\n",
      "Traceback (most recent call last):\n",
      "  File \"/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py\", line 917, in _bootstrap_inner\n",
      "    self.run()\n",
      "  File \"<ipython-input-2-e66d3c00927d>\", line 11, in run\n",
      "    if queue.qsize() < 1000:\n",
      "AttributeError: module 'queue' has no attribute 'qsize'\n",
      "Exception in thread Thread-7:\n",
      "Traceback (most recent call last):\n",
      "  File \"/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py\", line 917, in _bootstrap_inner\n",
      "    self.run()\n",
      "  File \"<ipython-input-2-e66d3c00927d>\", line 11, in run\n",
      "    if queue.qsize() < 1000:\n",
      "AttributeError: module 'queue' has no attribute 'qsize'\n",
      "\n",
      "\n",
      "Exception in thread Thread-8:\n",
      "Traceback (most recent call last):\n",
      "  File \"/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py\", line 917, in _bootstrap_inner\n",
      "    self.run()\n",
      "  File \"<ipython-input-2-e66d3c00927d>\", line 24, in run\n",
      "    if queue.qsize() < 100:\n",
      "AttributeError: module 'queue' has no attribute 'qsize'\n",
      "Exception in thread Thread-9:\n",
      "Traceback (most recent call last):\n",
      "  File \"/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py\", line 917, in _bootstrap_inner\n",
      "    self.run()\n",
      "  File \"<ipython-input-2-e66d3c00927d>\", line 24, in run\n",
      "    if queue.qsize() < 100:\n",
      "AttributeError: module 'queue' has no attribute 'qsize'\n",
      "\n",
      "\n",
      "Exception in thread Thread-11:\n",
      "Traceback (most recent call last):\n",
      "  File \"/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py\", line 917, in _bootstrap_inner\n",
      "    self.run()\n",
      "  File \"<ipython-input-2-e66d3c00927d>\", line 24, in run\n",
      "    if queue.qsize() < 100:\n",
      "AttributeError: module 'queue' has no attribute 'qsize'\n",
      "Exception in thread Thread-10:\n",
      "Traceback (most recent call last):\n",
      "  File \"/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py\", line 917, in _bootstrap_inner\n",
      "    self.run()\n",
      "  File \"<ipython-input-2-e66d3c00927d>\", line 24, in run\n",
      "    if queue.qsize() < 100:\n",
      "AttributeError: module 'queue' has no attribute 'qsize'\n",
      "\n",
      "\n",
      "Exception in thread Thread-12:\n",
      "Traceback (most recent call last):\n",
      "  File \"/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py\", line 917, in _bootstrap_inner\n",
      "    self.run()\n",
      "  File \"<ipython-input-2-e66d3c00927d>\", line 24, in run\n",
      "    if queue.qsize() < 100:\n",
      "AttributeError: module 'queue' has no attribute 'qsize'\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import threading\n",
    "import time\n",
    "import queue\n",
    "\n",
    "class Producter(threading.Thread):\n",
    "    def run(self):\n",
    "        global queue\n",
    "        count = 0\n",
    "        while True:\n",
    "            # qsize返回queue内容长度\n",
    "            if queue.qsize() < 1000:\n",
    "                for i in range(100):\n",
    "                    count = count + 1\n",
    "                    msg = '生产产品' + str(count)\n",
    "                    queue.put(msg)\n",
    "                    print(msg)\n",
    "            time.sleep(0.5)\n",
    "            \n",
    "class Customer(threading.Thread):\n",
    "    def run(self):\n",
    "        global queue\n",
    "        while True:\n",
    "            # qsize返回queue内容长度\n",
    "            if queue.qsize() < 100:\n",
    "                for i in range(3):\n",
    "                    # get是从queue中取出一个值\n",
    "                    msg = self.name + '消费了 ' + queue.get()\n",
    "                    print(msg)\n",
    "            time.sleep(1)\n",
    "            \n",
    "if __name__ == '__main__':\n",
    "    q = queue.Queue()\n",
    "    \n",
    "    for i in range(500):\n",
    "        q.put('初始产品' + str(i))\n",
    "    for i in range(2):\n",
    "        p = Producter()\n",
    "        p.start()\n",
    "    for i in range(5):\n",
    "        c = Customer()\n",
    "        c.start()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
